package com.ai.controller.made.ai_api;

import com.ai.annotation.EnterPathParamLog;
import com.ai.entity.made.Pictures;
import com.ai.entity.made.Slabs;
import com.ai.entity.made.Unusual;
import com.ai.model.made.AIUnusual;
import com.ai.model.made.LargeImageSubmit;
import com.ai.model.made.SmallImageSubmit;
import com.ai.networking.websocket.service.WebSocket;
import com.ai.networking.websocket.service.comm.CommonWebSocket;
import com.ai.networking.websocket.service.entity.WSMessage;
import com.ai.service.made.IPicturesService;
import com.ai.service.made.ISlabsService;
import com.ai.service.made.IUnusualService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 算法接口----图片提交
 * @author chen
 * @since 2023-04-03 21:17:12
 */
@RestController
@RequestMapping("/aiSubmit")
@Slf4j
public class AiSubmitController {

    @Resource
    ISlabsService slabsService;
    @Resource
    IPicturesService picturesService;

    @Resource
    IUnusualService unusualService;

    @Value("${nginx.path.images}")
    private String nginxImagesPath;

    @PostMapping("smallImage")
    @ApiModelProperty("小图提交")
    @EnterPathParamLog
    public void smallImage(@RequestBody @Valid SmallImageSubmit imageSubmit) throws ParseException {
        String slabNum = imageSubmit.getSlabNum();

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        /*
        判断板坯号是否已存在
        1. 已存在，则无视
        2. 不存在，则新增
         */
        if (!slabsService.isExist(slabNum)) {
            slabsService.save(new Slabs()
                    .setSlabNum(slabNum)
                    .setProductLines(imageSubmit.getProductLines()));
        }

        Pictures pictures = new Pictures()
                .setSlabNum(slabNum)
                .setSurface(imageSubmit.getSurface())
                .setNumber(imageSubmit.getNumber())
                .setPicture(imageSubmit.getPicture())
                .setCreateTime(simpleDateFormat.parse(imageSubmit.getSubmitTime()));

        picturesService.save(pictures);

        int picturesId = pictures.getId();
        List<AIUnusual> AIUnusualList = imageSubmit.getAiUnusualList();
        if (null != AIUnusualList && AIUnusualList.size()>0){
            for (AIUnusual aiUnusual : AIUnusualList) {
                Unusual unusual = new Unusual()
                        .setSlabNum(slabNum)
                        .setPicturesId(picturesId)
                        .setNumber(aiUnusual.getNumber())
                        .setStatus(aiUnusual.getStatus());
                unusualService.save(unusual);
            }
        }

    }

    @PostMapping("largeImage")
    @ApiModelProperty("大图提交")
    @EnterPathParamLog
    public void smallImage(@RequestBody LargeImageSubmit imageSubmit) throws ParseException {

        String slabNum = imageSubmit.getSlabNum();
        Slabs slabs;
        /*
        判断板坯号是否已存在
        1. 已存在，则修改
        2. 不存在，则新增
         */
        if (!slabsService.isExist(slabNum)) {
            slabs = new Slabs()
                    .setSlabNum(slabNum)
                    .setProductLines(imageSubmit.getProductLines());
            try {
                fillSlabsData(imageSubmit, slabs);
            } catch (ParseException e) {
                log.error("算法大图提交时间格式错误",e);
                log.error(e.getStackTrace().toString());
                throw new RuntimeException(e);
            }
            slabsService.save(slabs);
        } else {
            slabs = slabsService.getOne(new QueryWrapper<Slabs>().eq("slab_num", slabNum));
            try {
                fillSlabsData(imageSubmit, slabs);
            } catch (ParseException e) {
                log.error("算法大图提交时间格式错误",e);
                log.error(e.getStackTrace().toString());
                throw new RuntimeException(e);
            }
            slabsService.updateById(slabs);
        }
        /**
         * 这里提交后需要通过webSocket通知前端读取新数据
         */
        sendWebSocket();
        new Thread(()->{
            log.info("通过子线程执行下载图片任务" + Thread.currentThread());
            //下载图片
            //根据版批号，获取大图、小图 的绝对路径
            String slabNumber = imageSubmit.getSlabNum();
            //获取对应的所有大图
            List<Slabs> bigPictureList = slabsService.list(new QueryWrapper<Slabs>().eq("slab_num", slabNumber));
            //获取对应的所有小图
            List<Pictures> smallPictureList = picturesService.list(new QueryWrapper<Pictures>().eq("slab_num", slabNumber));
//            通过io流获取服务器中对应的位置，并转换到Nginx对应的图片目录下 nginxImagesPath

//            处理大图
            if (!CollectionUtils.isEmpty(bigPictureList)){
                bigPictureList.forEach(item->{
//                    处理上表面
                    if (!StringUtils.isBlank(item.getUpperPictures())){
                        //io读取存储图片  image-时间-产线-板坯号-上下表  1:上表面
                        try {
                            log.info("===============   开始下载大图上表面    ===============");
                            downloadPicture(item.getUpperPictures(),item.getUpperTime(),item.getProductLines(),item.getSlabNum(),"1",item.getId().toString(),"SLABS");
                            log.info("===============   大图上表面下载完成    ===============");

                        } catch (IOException e) {
                            log.error("==============服务器下载出现异常"+ e.getMessage()+"===================",e);
                            log.error(e.toString());
                            throw new RuntimeException(e);
                        }
                    }
                    //处理下表面
                    if (!StringUtils.isBlank(item.getLowerPictures())){
                        //io读取存储图片  image-时间-产线-板坯号-上下表  1:上表面
                        try {
                            log.info("===============   开始下载大图下表面    ===============");

                            downloadPicture(item.getLowerPictures(),item.getUpperTime(),item.getProductLines(),item.getSlabNum(),"2",item.getId().toString(),"SLABS");
                            log.info("===============   大图下表面下载完成    ===============");

                        } catch (IOException e) {
                            log.error("==============服务器下载出现异常"+ e.getMessage()+"===================",e);
                            log.error(e.toString());
                            throw new RuntimeException(e);
                        }
                    }
                });
            }
//            处理小图
            if (!CollectionUtils.isEmpty(smallPictureList)) {
                smallPictureList.forEach(item->{
                    if (!StringUtils.isBlank(item.getPicture())){
                        //io读取存储图片  image-时间-产线-板坯号-上下表  1:上表面
                        try {
                            log.info("===============   开始下载小图    ===============");
                            downloadPicture(item.getPicture(),item.getCreateTime(),imageSubmit.getProductLines(),item.getSlabNum(),item.getSurface().toString(),item.getId().toString(),"SMALL");
                            log.info("===============   小图下载完成    ===============");

                        } catch (IOException e) {
                            log.error("==============服务器下载出现异常"+ e.getMessage()+"===================",e);
                            log.error(e.toString());
                            throw new RuntimeException(e);
                        }
                    }
                });
            }
            //
        }).start();
    }

    /**
     *  通过io流获取文件，下载到本地
     *
     * @param picturesUrl  图片url
     * @param time  图片时间
     * @param productLines 产线
     * @param slabNum  版批号
     * @param surface  1:上表面，2：下表面
     * @param pictureId  图片记录id
     * @param type  大图小图标识
     */
    private void downloadPicture(String picturesUrl, Date time, Integer productLines, String slabNum, String surface , String pictureId, String type) throws IOException {
        InputStream is = null;
        FileOutputStream fileOutputStream = null;
        try {
            //创建图片url
            URL url = new URL(picturesUrl);
//        打开链接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//        设置请求方式
            conn.setRequestMethod("GET");
//        超时响应时间 10s
            conn.setConnectTimeout(10 * 1000);
//        通过输入流获取图片数据
            is = conn.getInputStream();
//        转换为二进制
            byte[] bytes = readInputStream(is);
            String filePath= new SimpleDateFormat("yyyyMMdd").format(time)+"/"
                    +productLines.toString()+"/"//产线
                    +slabNum+"/"//板胚号
                    +(surface.equals("1") ? "upperSurface" : "lowerSurface");
//        创建文件对象  image-时间-产线-板坯号-上下表  1:上表面
//            String fileName = picturesUrl.substring(picturesUrl.lastIndexOf("/") + 1, picturesUrl.lastIndexOf("."))//原文件名
//                    + "-" + new SimpleDateFormat("yyyyMMdd").format(time)//时间
//                    + "-" + productLines.toString()//产线
//                    + "-" + slabNum//板胚号
//                    + "-" + (surface.equals("1") ? "上表面" : "下表面")
//                    + picturesUrl.substring(picturesUrl.lastIndexOf("."));//文件后缀
            String fileName =picturesUrl.substring(picturesUrl.lastIndexOf("/") + 1);

//        String name = new String(fileName.getBytes("ISO-8859-1")).trim();
//        创建输出流，将文件输出到指定位置
            File file = new File(nginxImagesPath + "/" + filePath + "/" + fileName);//在指定位置创建文件
            if (!file.exists()) {//文件不存在
                //创建文件夹
                File dir = file.getParentFile();
                dir.mkdirs();//文件夹不存在，才会去创建
                file.createNewFile();
            }
            fileOutputStream = new FileOutputStream(file);
            //写入数据
            fileOutputStream.write(bytes);


            File images = new File(file.toPath().toString().substring(file.toPath().toString().lastIndexOf("images")-1));
            // : 2023/5/24 更新大图
            if (type.equals("SLABS") && surface.equals("1")) {
                //上表面
                slabsService.updateDownloadUPdPicture(images.toPath(),pictureId);
            }else if (surface.equals("2") && type.equals("SLABS")){
                slabsService.updateDownloadLOWERPicture(images.toPath(),pictureId);
            }
            // : 2023/5/24 更新小图
            if (type.equals("SMALL")){
                picturesService.updateDownloadPicture(images.toPath(),pictureId);
            }


        } finally {
            if (null != is ){
                is.close();
            }
            if (null != fileOutputStream){
                fileOutputStream.close();
            }
        }
    }
    public static byte[] readInputStream(InputStream inStream) throws IOException {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        //创建一个Buffer字符串
        byte[] buffer = new byte[6024];
        //每次读取的字符串长度，如果为-1，代表全部读取完毕
        int len;
        //使用一个输入流从buffer里把数据读取出来
        while ((len = inStream.read(buffer)) != -1) {
            //用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度
            outStream.write(buffer, 0, len);
        }
        //关闭输入流
        inStream.close();
        //把outStream里的数据写入内存
        return outStream.toByteArray();
    }


    public void fillSlabsData(LargeImageSubmit imageSubmit, Slabs slabs) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Slabs unSlabs = unusualService.getUnusual(slabs.getSlabNum());

        if (imageSubmit.getSurface() == 1) {
//            slabs.setUpperVisible(1)
//                    .setUpperTime(simpleDateFormat.parse(imageSubmit.getSubmitTime()))
//                    .setUpperPictures(imageSubmit.getPicture());
            slabs.setUpperTime(simpleDateFormat.parse(imageSubmit.getSubmitTime()))
                    .setUpperPictures(imageSubmit.getPicture());
        } else {
//            slabs.setLowerVisible(1)
//                    .setLowerTime(simpleDateFormat.parse(imageSubmit.getSubmitTime()))
//                    .setLowerPictures(imageSubmit.getPicture());
            slabs.setLowerTime(simpleDateFormat.parse(imageSubmit.getSubmitTime()))
                    .setLowerPictures(imageSubmit.getPicture());
        }
//        slabs.setUnusual1(unSlabs.getUnusual1())
        slabs.setUpperVisible(1);
        /**
         * 没有异常，填充0
         */
        if ( null == unSlabs ){
            slabs.setUnusual1(0)
                    .setUnusual2(0)
                    .setUnusual3(0)
                    .setUnusual4(0)
                    .setUnusual5(0);
        }else {
            slabs.setUnusual1(unSlabs.getUnusual1())
                    .setUnusual2(unSlabs.getUnusual2())
                    .setUnusual3(unSlabs.getUnusual3())
                    .setUnusual4(unSlabs.getUnusual4())
                    .setUnusual5(unSlabs.getUnusual5());
        }
    }

    private void sendWebSocket() {
        WSMessage wsMessage = new WSMessage();
        wsMessage.setContent("UPDATE");
        CopyOnWriteArraySet<WebSocket> webSockets = CommonWebSocket.WS_SOCKET_SET;
        webSockets.forEach(ws ->
                ws.sendMessage(wsMessage)
        );
    }
}
